package cn.iocoder.yudao.module.business.service.trainUnit;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.business.client.ZljcClient;
import cn.iocoder.yudao.module.business.controller.admin.trainUnit.vo.TrainUnitPageReqVO;
import cn.iocoder.yudao.module.business.controller.admin.trainUnit.vo.TrainUnitSaveReqVO;
import cn.iocoder.yudao.module.business.dal.dataobject.trainUnit.TrainUnitDO;
import cn.iocoder.yudao.module.business.dal.mysql.trainUnit.TrainUnitMapper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.business.enums.ErrorCodeConstants.TRAIN_UNIT_NOT_EXISTS;
import static cn.iocoder.yudao.module.business.enums.ErrorCodeConstants.TRAIN_UNIT_REPEAT_NAME;

/**
 * 培训单位 Service 实现类
 *
 * @author admin
 */
@Service
@Validated
public class TrainUnitServiceImpl implements TrainUnitService {

    private static final String DATE_PATTERN = "yyyy-MM-dd";


    @Resource
    private TrainUnitMapper trainUnitMapper;

    @Override
    public Long createTrainUnit(TrainUnitSaveReqVO createReqVO) {
        // 校验存在
        validateTrainUnitExists(null,createReqVO.getTrainUnitName());
        // 插入
        TrainUnitDO trainUnit = BeanUtils.toBean(createReqVO, TrainUnitDO.class);
        trainUnitMapper.insert(trainUnit);
        // 返回
        return trainUnit.getId();
    }

    @Override
    public void updateTrainUnit(TrainUnitSaveReqVO updateReqVO) {
        // 校验存在
        validateTrainUnitExists(updateReqVO.getId(), updateReqVO.getTrainUnitName());
        // 更新
        TrainUnitDO updateObj = BeanUtils.toBean(updateReqVO, TrainUnitDO.class);
        trainUnitMapper.updateById(updateObj);
    }

    @Override
    public void deleteTrainUnit(Long id) {
        // 校验存在
        validateTrainUnitExists(id,null);
        // 删除
        trainUnitMapper.deleteById(id);
    }

    private void validateTrainUnitExists(Long id,String name) {
        if (id!=null){
            TrainUnitDO trainUnitDO = trainUnitMapper.selectById(id);
            if (trainUnitDO == null){
                throw exception(TRAIN_UNIT_NOT_EXISTS);

            }
        }

        if (StringUtils.isNotBlank(name)){
            TrainUnitDO dbTrainUnit = trainUnitMapper.selectByName(name);
            if (dbTrainUnit!=null){
                if (id == null){
                    throw exception(TRAIN_UNIT_REPEAT_NAME,name);
                }
                if (!dbTrainUnit.getId().equals(id)){
                    throw exception(TRAIN_UNIT_REPEAT_NAME,name);
                }
            }
        }
    }

    @Override
    public TrainUnitDO getTrainUnit(Long id) {
        return trainUnitMapper.selectById(id);
    }

    @Override
    public PageResult<TrainUnitDO> getTrainUnitPage(TrainUnitPageReqVO pageReqVO) {
        return trainUnitMapper.selectPage(pageReqVO);
    }


    /**
     * 同步培训单位
     * @param pageReqVO 分页参数
     * @return 同步条数
     */
    @Override
    public int executeSyncTrainUnit(TrainUnitPageReqVO pageReqVO) {

        //每次请求条数设置，总条数，总页数
        pageReqVO.setPageSize(100);
        int total = 0;
        AtomicInteger totalPageNo = new AtomicInteger(1) ;
        List<TrainUnitDO> trainUnitList = ZljcClient.getTrainUnit(1,totalPageNo,pageReqVO);
        total = total +trainUnitList.size();
        addTrainUnit(trainUnitList);
        for (int i = 2; i <= totalPageNo.get() ; i++) {
            trainUnitList = ZljcClient.getTrainUnit(i,totalPageNo,pageReqVO);
            if (CollectionUtil.isEmpty(trainUnitList)){
                break;
            }
            addTrainUnit(trainUnitList);
            total = total + trainUnitList.size();
        }

        return total;
    }


    /**
     * 添加培训单位
     * @param trainUnits list
     */
    public void addTrainUnit(List<TrainUnitDO> trainUnits){
        Set<Long> ids = trainUnits.stream().map(TrainUnitDO::getId).collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(ids)){
            return;
        }
        List<TrainUnitDO> dbList = trainUnitMapper.selectListByRelationIds(ids);
        Map<Long, TrainUnitDO> collect = dbList.stream().collect(Collectors.toMap(TrainUnitDO::getRelationId, Function.identity(), (v1, v2) -> v1));


        List<TrainUnitDO> insertList = new ArrayList<>();
        List<TrainUnitDO> updateList = new ArrayList<>();
        List<Long> deleteList = new ArrayList<>();
        for (TrainUnitDO unitDO : trainUnits){
            if (unitDO.getDeleted()){
                deleteList.add(unitDO.getId());
                continue;
            }
            TrainUnitDO existDo = collect.get(unitDO.getId());
            unitDO.setRelationId(unitDO.getId());
            if (existDo==null){
                unitDO.setId(null);
                insertList.add(unitDO);
            }else{
                unitDO.setId(existDo.getId());
                updateList.add(unitDO);
            }
        }

        if (CollectionUtil.isNotEmpty(deleteList)){
            trainUnitMapper.deleteTrainUnitList(deleteList);
        }

        if (CollectionUtil.isNotEmpty(insertList)){
            trainUnitMapper.insertBatch(insertList);
        }

        if (CollectionUtil.isNotEmpty(updateList)){
            //每x条数据执行一次sql
            List<List<TrainUnitDO>> partition = Lists.partition(updateList, 100);
            for (List<TrainUnitDO> updates : partition){
                trainUnitMapper.updateTrainUnitList(updates);
            }
        }
    }

}